#ifndef DIO_BLOCKQUEUE_H_
#define DIO_BLOCKQUEUE_H_

#include <fermat/common/cond.h>
#include <fermat/common/mutex.h>
#include <fermat/common/scoped_lock.h>
#include <deque>
#include <assert.h>
#include <algorithm>

namespace fermat {

template<typename T>
    
class BlockedQueue {
public:
    BlockedQueue()
      : _mutex(),
        _notEmpty(),
        _queue()
    {
    }

    void put(const T& x)
    {
        ScopedMutex lock(&_mutex);
        _queue.push_back(x);
        _notEmpty.signal();
    }

    T take()
    {
        ScopedMutex lock(&_mutex);
        while (_queue.empty()) {
            _notEmpty.wait(&_mutex);
        }
        assert(!_queue.empty());
        T front(_queue.front());
        _queue.pop_front();
        return front;
    }

    T takeTimeOut(int64_t usec)
    {
        ScopedMutex lock(&_mutex);
        if(_queue.empty()) {
            _notEmpty.wait(&_mutex, usec);
        }

        if(_queue.empty()) {
            return T();
        }
        
        T front(_queue.front());
        _queue.pop_front();
        return front;
    }
    bool erase(const T & x)
    {
        ScopedMutex lock(&_mutex);
        if(_queue.empty()) {
            return false;
        }
        typename std::deque<T>::iterator it = std::find(_queue.begin(), _queue.end(), x);
        if(it != _queue.end()) {
            _queue.erase(it);
            return true;
        }
        return false;
    }
    size_t size()
    {
        ScopedMutex lock(&_mutex);
        return _queue.size();
    }

private:
    Mutex             _mutex;
    Cond              _notEmpty;
    std::deque<T>     _queue;
};

}

#endif
